package com.example.tjremark.service.impl;

import com.example.tjremark.constant.RedisConstants;
import com.example.tjremark.domain.dto.LikeRecordFormDTO;
import com.example.tjremark.domain.dto.LikedTimesDTO;
import com.example.tjremark.domain.po.LikedRecord;
import com.example.tjremark.mapper.LikedRecordMapper;
import com.example.tjremark.service.ILikedRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.utils.BooleanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 *
 * @author yp
 * @since 2024-07-29
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LikedRecordServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {

    private final RabbitMqHelper rabbitMqHelper;
    private final StringRedisTemplate redisTemplate;

    /**
     * 点赞或者取消点赞
     *
     * @param dto
     */
    @Override
    public void addLikeRecord(LikeRecordFormDTO dto) {
        //1,判断点赞类型，点赞，取消点赞
        boolean success = dto.getLiked() ? like(dto) : unlike(dto);

        //2,判断操作是否成功
        if (success) {
            //3.发送当前的业务的点赞数量 存放redisZSt里面
            String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + dto.getBizType() + ":" + dto.getBizId();
            Long likeTimes = redisTemplate.opsForSet().size(key);
            if (likeTimes == null) {
                return;
            }
            //eg:likes:times:type:QA
            redisTemplate.opsForZSet().add(RedisConstants.LIKES_TIMES_KEY_PREFIX + dto.getBizType(), dto.getBizId().toString(), likeTimes);
        }
    }

    @Override
    public Set<Long> queryListUserIdAndIds(String bizType, List<Long> bizIds) {
        Set<Long> set = new HashSet<>();
        //根据用户id和ids查询点赞的状态,业务类型
        Long userId = UserContext.getUser();
        //返回值：就是管道内多条命令的（多个操作的集合）的结果的集合
        // 1         2      3        4
        // true      false true     false
        List<Object> objects = redisTemplate.executePipelined(
                new RedisCallback<Object>() {
                    @Override
                    public Object doInRedis(RedisConnection connection) throws DataAccessException {
                        //把操作redis放在doInRedis（）；就在管道里面执行批量操作
                        StringRedisConnection conn = (StringRedisConnection) connection;
                        //bizids[1,2,3,4,5,6,7,8,9,10]
                        for (Long bizId : bizIds) {
                            String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + bizType + ":" + bizId;
                            conn.sIsMember(key, userId.toString());
                        }
                        return null;
                    }
                }
        );
        for (int i = 0; i < objects.size(); i++) {
            Boolean result = (Boolean) objects.get(i);
            if (result) {
                set.add(bizIds.get(i));
            }
        }

        /**
         for (Long bizId : bizIds) {
         String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + bizType + ":" +bizId;
         Boolean member = redisTemplate.opsForSet().isMember(key, userId);
         if(BooleanUtils.isTrue(member)){
         set.add(bizId);
         }
         }
         **/
        //2，返回点赞的业务id；
        return set;
    }


    /**
     * 批量读取Redis里面的点赞数量的数据，发给MQ;
     *
     * @param biz_type
     * @param maxBizSize
     */
    @Override
    public void readLikedTimesAndSendMessage(String biz_type, int maxBizSize) {
        //1.从redis里面取数据
        String key = RedisConstants.LIKES_TIMES_KEY_PREFIX + biz_type;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(key, maxBizSize);
        if (CollUtils.isEmpty(typedTuples)) {
            return;
        }
        //2.封装成LikedTimesDTO集合
        List<LikedTimesDTO> dtoList = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            String bizId = typedTuple.getValue();
            Double likedTimes = typedTuple.getScore();
            if (bizId == null || likedTimes == null) {
                continue;
            }
            dtoList.add(new LikedTimesDTO(Long.valueOf(bizId), likedTimes.intValue()));
        }
        rabbitMqHelper.send(MqConstants.Exchange.LIKE_RECORD_EXCHANGE, StringUtils.format(MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE, biz_type),
                dtoList);
    }


    //取消点赞
    private boolean unlike(LikeRecordFormDTO dto) {
        Long userId = UserContext.getUser();
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + dto.getBizType() + ":" + dto.getBizId();
        //2.从Set里面移除元素
        Long result = redisTemplate.opsForSet().remove(key, userId.toString());
        if (result != null) {
            return result > 0;
        }
        return false;
    }

    //点赞
    private boolean like(LikeRecordFormDTO dto) {
        //1.拼接key 业务类型：业务id(eg : likes:set:biz:QA:10 , 用户id)
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + dto.getBizType() + ":" + dto.getBizId();
        //1向Set里面放元素
        Long userId = UserContext.getUser();
        Long result = redisTemplate.opsForSet().add(key, userId.toString());
        if (result != null) {
            return result > 0;
        }
        return false;
    }
}
